﻿Option Explicit On
Option Strict On

Namespace Framework.Hardware

    ''' <summary>
    '''
    ''' </summary>
    ''' <remarks></remarks>
    Public Class ACOM2000Connection
        Implements IDisposable

#Region " Events"

        Public Event ForwardPowerLedUpdated As EventHandler(Of PowerLedEventArgs) 'Triggered when the Forward Power LED is updated
        Public Event ReflectedPowerLedUpdated As EventHandler(Of PowerLedEventArgs) 'Triggered when the Reflected Power LED is updated
        Public Event BandMotorPositionUpdated As EventHandler(Of MotorPositionEventArgs) 'Triggered when the Position of the Band Motor is reported
        Public Event LoadMotorPositionUpdated As EventHandler(Of MotorPositionEventArgs) 'Triggered when the Position of the Load Motor is reported
        Public Event TuneMotorPositionUpdated As EventHandler(Of MotorPositionEventArgs) 'Triggered when the Position of the Tune Motor is reported
        Public Event PowerOffExecuted As EventHandler(Of EventArgs) 'Triggered when power off is executed
        Public Event PowerOnExecuted As EventHandler(Of EventArgs) 'Triggered when the ACOM2000A powers on
        Public Event HVOnExecuted As EventHandler(Of EventArgs) 'Triggered when the High Voltage is powered on and the ACOM2000A is ready
        Public Event PowerOffCoolingTubes As EventHandler(Of EventArgs) 'Triggered while the ACOM2000A is powering off and begins cooling the tubes
        Public Event PowerOffComplete As EventHandler(Of EventArgs) 'Triggered when the Power off of the ACOM2000A is complete
        Public Event OperateModeOn As EventHandler(Of EventArgs) 'Triggered when the ACOM2000A switches to Operate Mode
        Public Event StandbyModeOn As EventHandler(Of EventArgs) 'Triggered when the ACOM2000A switches to StandBy Mode
        Public Event LEDStatusUpdate As EventHandler(Of LEDStatusEventArgs) 'Triggered when the status of one of the RCU Led's (not fwd or rfl power) changes
        Public Event RemotePowerOnStarted As EventHandler(Of EventArgs) 'Triggered when remote power on is started
        Public Event RemotePowerOnFinished As EventHandler(Of EventArgs) 'Triggered when remote power on is finished
        Public Event ConnectionTimeout As EventHandler(Of EventArgs) 'Triggered when the connection does not detect an ACOM2000A within the timeout period
        Public Event UnknownMessage As EventHandler(Of UnknownMessageEventArgs) 'Event Triggered when an unknown message is received 
        Public Event ConnectionOpened As EventHandler(Of EventArgs) 'Event Triggered when the COM Port is opened to the ACOM2000A
        Public Event ConnectionClosed As EventHandler(Of EventArgs) 'Event Triggered when the COM Port is closed to the ACOM2000A
        Public Event ACOM2000ADetected As EventHandler(Of ACOM2000ADetectedEventArgs) 'Event Triggered when Auto Detection is enabled and an ACOM2000A is detected on the network
        Public Event AirTemperatureChanged As EventHandler(Of AirTemperatureEventArgs) 'Triggered to update the air temperature
        Public Event BandFrequencyChanged As EventHandler(Of BandFrequencyEventArgs) 'Triggered when the band, frequency or antenna change
        Public Event AmplifierInfoReceived As EventHandler(Of AmplifierInfoEventArgs)
        Public Event AmplifierError As EventHandler(Of ErrorEventArgs) 'Triggered when an error is received from the amplifier
        <System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId:="RCUIs")> _
        Public Event RCUIsMeasuring As EventHandler(Of EventArgs) 'Triggered when the RCU is measuring
        Public Event MeasurementMetricUpdated As EventHandler(Of MeasurementMetricUpdatedEventArgs) 'Triggered when a measurement metric is updated

#End Region

#Region " Private Members "

        Private WithEvents m_RS232 As New Framework.RS232.RS232Port 'The RS232 Connection
        Private m_COMPort As String 'The COM Port to use to connect
        Private m_UseAutoDetection As Boolean = True 'Should we use auto detection to determine the ACOM2000A's Network Address
        Private m_ACOM2000Detected As Boolean 'Have we detected an ACOM2000A on the network
        Private m_DisconnectOnTimeout As Boolean = True  'Should the COM port be disconnected when no ACOM2000A is detected?
        Private m_Buffer() As Byte = New Byte() {} 'The Buffer used for incoming data from the ACOM2000A

        'ACOM RS232 Network Addresses
        Private m_ACOMNetworkACOM2000AAddress As Integer = &H41 'The Address of the ACOM2000A on the ACOM RS232 Network
        Private m_ACOMNetworkConnectionAddress As Integer = &H71 'The Address of the PC Controller on the ACOM RS232 Network

        Private m_Timeout As Integer = 5 'Connection timeout in seconds
        Private WithEvents m_TimeoutTimer As New Timers.Timer(m_Timeout * 1000)

        'Remote Power On
        Private m_WasConnectedBeforePowerON As Boolean 'Flag to determine if the RS232 port was open before the remote power on sequence was initiated
        Private WithEvents m_PowerOnTimer As New Timers.Timer(3000) 'The Timer used when performing a remote power on
        Private m_RemotePowerOnRS232Connection As Framework.RS232.RS232Port 'RS232 Connection used for powering on the ACOM2000A

#End Region

#Region " Public Methods "

        ''' <summary>
        ''' Connects to the ACOM2000A
        ''' </summary>
        ''' <param name="Port">The COM Port to use when connecting to the ACOM2000A</param>
        ''' <remarks></remarks>
        Public Sub Connect(ByVal Port As String)

            'Are we already connected? If so then disconnect first
            If IsConnected Then
                Disconnect()
            End If

            m_COMPort = Port

            If m_UseAutoDetection Then
                m_ACOM2000Detected = False
                m_ACOMNetworkACOM2000AAddress = 0
            Else
                m_ACOM2000Detected = True
            End If

            'Clear the Buffer
            m_Buffer = New Byte() {}

            'Force the COM Port closed just in case
            Framework.RS232.RS232Port.ForcePortClosed(m_COMPort)

            'Open the RS232 Port
            Dim RS232Parameters As New Framework.RS232.RS232PortParameters(1200, m_COMPort, False, False, IO.Ports.StopBits.One, 8, IO.Ports.Handshake.None, IO.Ports.Parity.None)
            m_RS232.Connect(RS232Parameters)

            If UseAutoDetection Then
                m_TimeoutTimer.Start()
            End If

            RaiseEvent ConnectionOpened(Me, New EventArgs())

        End Sub

        ''' <summary>
        ''' Disconnects from the ACOM2000A
        ''' </summary>
        ''' <remarks></remarks>
        Public Sub Disconnect()
            If m_RS232.IsOpen Then
                m_RS232.Disconnect()
                RaiseEvent ConnectionClosed(Me, New EventArgs())
            End If
        End Sub

#End Region

#Region " Public Properties "

        ''' <summary>
        ''' Should the COM port be disconnected when no ACOM2000A is detected?
        ''' </summary>
        ''' <value></value>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Public Property DisconnectOnTimeout As Boolean
            Get
                Return m_DisconnectOnTimeout
            End Get
            Set(ByVal value As Boolean)
                m_DisconnectOnTimeout = value
            End Set
        End Property

        ''' <summary>
        ''' The connection timeout in seconds
        ''' </summary>
        ''' <value></value>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Public Property Timeout As Integer
            Get
                Return m_Timeout
            End Get
            Set(ByVal value As Integer)
                m_Timeout = value
                m_TimeoutTimer.Interval = m_Timeout * 1000
            End Set
        End Property

        ''' <summary>
        ''' The Address of the ACOM2000A on the ACOM RS232 Network, Defaults to 0x41.
        ''' This is only used when Autodetection is turned off
        ''' </summary>
        ''' <value></value>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Public Property ACOMNetworkACOM2000AAddress As Integer
            Get
                Return m_ACOMNetworkACOM2000AAddress
            End Get
            Set(ByVal value As Integer)

                'Check the value is within the acceptable range
                If value < Constants.LOWEST_AMPLIFIER_ADDRESS Or value > Constants.HIGHEST_AMPLIFIER_ADDRESS Then
                    Throw New ArgumentOutOfRangeException("value", "The ACOM2000A Network Address must be between 0x40 (Hex) and 0x4F (Hex)")
                End If

                m_ACOMNetworkACOM2000AAddress = value
            End Set
        End Property

        ''' <summary>
        ''' The Address of the PC Controller on the ACOM RS232 Network, Defaults to 0x71
        ''' </summary>
        ''' <value></value>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Public Property ACOMNetworkConnectionAddress As Integer
            Get
                Return m_ACOMNetworkConnectionAddress
            End Get
            Set(ByVal value As Integer)

                'Check the value is within the acceptable range
                If value < Constants.LOWEST_PCCONTROLLER_ADDRESS Or value > Constants.HIGHEST_PCCONTROLLER_ADDRESS Then
                    Throw New ArgumentOutOfRangeException("value", "The ACOM Connection Network Address must be between 0x70 (Hex) and 0x7F (Hex)")
                End If

                m_ACOMNetworkConnectionAddress = value
            End Set
        End Property

        ''' <summary>
        ''' Should we use auto detection to determine the ACOM2000A's Network Address
        ''' </summary>
        ''' <value></value>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Public Property UseAutoDetection As Boolean
            Get
                Return m_UseAutoDetection
            End Get
            Set(ByVal value As Boolean)
                m_UseAutoDetection = value
            End Set
        End Property

        ''' <summary>
        ''' The COM Port the ACOM2000A is connected on
        ''' </summary>
        ''' <value></value>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Public ReadOnly Property COMPort As String
            Get
                Return m_COMPort
            End Get
        End Property

        ''' <summary>
        ''' Are we connected to the ACOM2000A
        ''' </summary>
        ''' <value></value>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Public ReadOnly Property IsConnected As Boolean
            Get
                Return m_RS232.IsOpen
            End Get
        End Property

        ''' <summary>
        ''' Have we detected an ACOM2000A on the RS232 Network?
        ''' </summary>
        ''' <value></value>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Public ReadOnly Property ACOM2000Detected As Boolean
            Get
                Return m_ACOM2000Detected
            End Get
        End Property

#End Region

#Region " RS232 Handlers "

        ''' <summary>
        ''' Data Received from the RS232 connection
        ''' </summary>
        ''' <param name="sender"></param>
        ''' <param name="e"></param>
        ''' <remarks></remarks>
        Private Sub m_RS232_DataReceived(ByVal sender As Object, ByVal e As Framework.RS232.RS232DataReceivedEventArgs) Handles m_RS232.DataReceived
            DecodeMessages(e.ByteData)
        End Sub

        Private Sub m_RS232_PortClosed(sender As Object, e As System.EventArgs) Handles m_RS232.PortClosed
            m_TimeoutTimer.Stop()

            If UseAutoDetection Then
                m_TimeoutTimer.Stop()
            End If

            RaiseEvent ConnectionClosed(Me, New EventArgs())

            'TODO: Should probably have a way of giving a connection error as this is the only reason why this event would be called
        End Sub

#End Region

#Region " Message Processor "

        ''' <summary>
        ''' Decodes the Messages received from the COM Port and Sends them to the message processor
        ''' </summary>
        ''' <param name="Data"></param>
        ''' <remarks></remarks>
        Public Sub DecodeMessages(ByVal Data() As Byte)

            'Check Data Isn't Nothing 
            If Data Is Nothing Then
                Throw New ArgumentNullException("Data")
            End If

            Dim MessageList As New Generic.List(Of ACOMMessage)

            Dim OldBufferLength As Integer = m_Buffer.Length
            Array.Resize(m_Buffer, m_Buffer.Length + Data.Length)
            Array.Copy(Data, 0, m_Buffer, OldBufferLength, Data.Length)

            'Split up commands
            Dim CommandStart As Integer = 0
            For i As Integer = 0 To m_Buffer.GetUpperBound(0)
                If (m_Buffer(i) >= Constants.FORWARD_POWER_LED_MESSAGE_LOWESTVALUE And m_Buffer(i) <= Constants.FORWARD_POWER_LED_MESSAGE_HIGESTVALUE) Or (m_Buffer(i) >= Constants.REFLECTED_POWER_LED_MESSAGE_LOWESTVALUE And m_Buffer(i) <= Constants.REFLECTED_POWER_LED_MESSAGE_HIGESTVALUE) Then
                    Dim CommandData(0) As Byte
                    CommandData(0) = m_Buffer(i)
                    MessageList.Add(New ACOMMessage(CommandData))
                    CommandStart = i + 1
                ElseIf m_Buffer(i) = 0 Or m_Buffer(i) = 13 Then '&H00 and &H0D are end of command terminators
                    Dim CommandData((i - CommandStart) - 1) As Byte
                    Array.Copy(m_Buffer, CommandStart, CommandData, 0, CommandData.Length)
                    If CommandData.Length > 0 Then
                        MessageList.Add(New ACOMMessage(CommandData))
                    End If
                    CommandStart = i + 1
                End If
            Next

            'If this is the end of the buffer then clear the buffer
            If CommandStart = m_Buffer.Length Then
                m_Buffer = New Byte() {}
            ElseIf CommandStart = 0 Then
                'Do nothing, the whole buffer needs storing
            Else 'Save the remainder for processing next 
                Dim WorkingBuffer() As Byte = DirectCast(m_Buffer.Clone, Byte())
                Array.Resize(m_Buffer, m_Buffer.Length - CommandStart)
                Array.Copy(WorkingBuffer, CommandStart, m_Buffer, 0, m_Buffer.Length)
            End If

            'Process the commands
            ProcessMessages(MessageList)

        End Sub

        ''' <summary>
        ''' Processes Messages Received from the COM Port
        ''' </summary>
        ''' <param name="MessageList"></param>
        ''' <remarks></remarks>
        Private Sub ProcessMessages(ByVal MessageList As Generic.List(Of ACOMMessage))

            For Each Message As ACOMMessage In MessageList

                'Is the message intended for me?
                If Not Message.DestinationAddress = m_ACOMNetworkConnectionAddress And Not Message.DestinationAddress = Constants.ACOMNETWORK_BROADCAST_ADDRESS Then
                    Exit Sub
                End If

                Select Case Message.MessageType
                    Case "FORWARDPOWERLED"
                        HandleMessageForwardPowerLED(Message)
                    Case "REFLECTEDPOWERLED"
                        HandleMessageReflectedPowerLED(Message)
                    Case "A" 'BAND Motor Position
                        HandleMessageBANDMotorPosition(Message)
                    Case "B" 'LOAD Motor Position
                        HandleMessageLOADMotorPosition(Message)
                    Case "C" 'TUNE Motor Position
                        HandleMessageTUNEMotorPosition(Message)
                    Case "E" 'Amplifier Error
                        HandleMessageAmplifierError(Message)
                    Case "G1" 'SRAM Contents
                        'TODO: Add support for G1-SRAM Content message type
                    Case "H" 'Motors are in home position
                        'TODO: Add support for H-Motors in home position message type
                    Case "I" 'Air Temperature (x 10deg C), LCD Bars Position
                        HandleMessageAirTemperature(Message)
                    Case "L" 'This is the Broadcast address identifier message
                        HandleMessageBroadcastID(Message)
                    Case "R" 'Amplifier Individual Data
                        'TODO: Add support for R-Amplifier individual data message type
                    Case "P" 'Input Power Marker Position
                        'TODO: Add support for P-Input power marker message type
                    Case "Q" 'Autotune
                        'TODO: Add support for Q-Autotune message type
                    Case "Q3" 'Preceeds Error Message when not in auto tune
                        'TODO: Add support for Q3 message type
                    Case "V" 'Error flag?
                        'TODO: Add support for V message type
                    Case "G3" 'EEPROM Contents
                        HandleMessageEEPROMContents(Message)
                    Case "O" 'Operate Mode On
                        HandleMessageOperateModeOn()
                    Case "S" 'StandBy Mode On
                        HandleMessageStandbyModeOn()
                    Case "U" 'LED Status
                        HandleMessageLEDStatus(Message)
                    Case "W1" 'Current Segment Info
                        HandleMessageCurrentSegmentInfo(Message)
                    Case "MM" 'The RCU is in measuring mode
                        HandleMessageRCUEnteredMeasureMode()
                    Case "0" 'Power Off Executed
                        HandleMessagePowerOffExecuted()
                    Case "1" 'Power On Executed
                        HandleMessagePowerOnExecuted()
                    Case "2" 'HV On
                        HandleMessageHVOn()
                    Case "3" 'Power Off But still cooling tubes
                        HandleMessagePowerOffCoolingTubes()
                    Case "4" 'Power Off Complete
                        HandleMessagePowerOffComplete()
                    Case "b" 'MeasurementMetricType.Bias '= xx/2,V
                        HandleMessageMeasurementBias(Message)
                    Case "e" 'MeasurementMetricType.DCInput '= xx*yy*0,16, W
                        HandleMessageMeasurementDCInput(Message)
                    Case "f" 'MeasurementMetricType.Drive '= xx*xx/512, W
                        HandleMessageMeasurementDrive(Message)
                    Case "h" 'MeasurementMetricType.Frequency '= (xxyy)*2, kHz
                        HandleMessageMeasurementFrequency(Message)
                    Case "i" 'MeasurementMetricType.ForwardPower '= xx*xx/16, W
                        HandleMessageMeasurementForwardPower(Message)
                    Case "j" 'MeasurementMetricType.FilamentVoltage '= xx/16, V
                        HandleMessageMeasurementFilamentVoltage(Message)
                    Case "k" 'MeasurementMetricType.PowerGain '= 10*lg(xx*xx/yy/yy*32), dB
                        HandleMessageMeasurementPowerGain(Message)
                    Case "l" 'MeasurementMetricType.HV '= xx*16, V
                        HandleMessageMeasurementHV(Message)
                    Case "m" 'MeasurementMetricType.IFFrontTube '= xx/16, A
                        HandleMessageMeasurementIFFrontTube(Message)
                    Case "n" 'MeasurementMetricType.IFRearTube '=xx/16, A
                        HandleMessageMeasurementIFRearTube(Message)
                    Case "o" 'MeasurementMetricType.GridCurrent '= xx/10, mA
                        HandleMessageMeasurementGridCurrent(Message)
                    Case "p" 'MeasurementMetricType.PlateCurrent '= xx*10, mA
                        HandleMessageMeasurementPlateCurrent(Message)
                    Case "q" 'MeasurementMetricType.ScreenCurrent '= xx, mA
                        HandleMessageMeasurementScreenCurrent(Message)
                    Case "r" 'MeasurementMetricType.MainsVoltage '= xx*10/8, V
                        HandleMessageMeasurementMainsVoltage(Message)
                    Case "s" 'MeasurementMetricType.PlateRFVoltage '= xx*12, V
                        HandleMessageMeasurementPlateRFVoltage(Message)
                    Case "t" 'MeasurementMetricType.ReflectedPower '= xx*xx/100, W
                        HandleMessageMeasurementReflectedPower(Message)
                    Case "w" 'MeasurementMetricType.ScreenVoltage '= xx*2, V
                        HandleMessageMeasurementScreenVoltage(Message)
                    Case "x" 'MeasurementMetricType.FrontTubeTemp '= (xx-136)*2, oC
                        HandleMessageMeasurementFrontTubeTemp(Message)
                    Case "y" 'MeasurementMetricType.RearTubeTemp '= (xx-136)*2, oC
                        HandleMessageMeasurementRearTubeTemp(Message)
                    Case "z" 'MeasurementMetricType.VSWR '= (2,5*xx+yy)/(2,5*xx-yy)
                        HandleMessageMeasurementVSWR(Message)
                    Case Else
                        'Unknown Message so print debug info
                        Dim DebugString As String = ""
                        DebugString &= "From: " & Hex(Message.SourceAddress)
                        DebugString &= " To: " & Hex(Message.DestinationAddress)
                        DebugString &= " Command: " & Message.MessageType
                        DebugString &= " Data: "
                        If Message.Parameters IsNot Nothing Then
                            For i As Integer = 0 To Message.Parameters.GetUpperBound(0)
                                If Not i = 0 Then
                                    DebugString &= ":"
                                End If
                                DebugString &= Hex(Message.Parameters(i))
                            Next
                        End If

                        RaiseEvent UnknownMessage(Me, New UnknownMessageEventArgs(DebugString))
                End Select

            Next

        End Sub

#Region " Command Handlers "

        Private Sub HandleMessageMeasurementBias(Message As ACOMMessage)
            If MeasurementMetricUpdatedEvent IsNot Nothing Then
                Dim xx As Integer = ((Message.Parameters(0) - 48) * 16) + (Message.Parameters(1) - 48)
                Dim Value As Integer = CInt(xx / 2)
                RaiseEvent MeasurementMetricUpdated(Me, New MeasurementMetricUpdatedEventArgs(MeasurementMetricType.Bias, "-" & Value.ToString & "V"))
            End If
        End Sub

        Private Sub HandleMessageMeasurementDCInput(Message As ACOMMessage)
            If MeasurementMetricUpdatedEvent IsNot Nothing Then
                Dim xx As Integer = ((Message.Parameters(0) - 48) * 16) + (Message.Parameters(1) - 48)
                Dim yy As Integer = ((Message.Parameters(2) - 48) * 16) + (Message.Parameters(3) - 48)

                Dim Value As Double = (xx * yy * 0.16) / 1000
                RaiseEvent MeasurementMetricUpdated(Me, New MeasurementMetricUpdatedEventArgs(MeasurementMetricType.DCInput, Value.ToString("0.00") & "kW"))
            End If
        End Sub

        Private Sub HandleMessageMeasurementDrive(Message As ACOMMessage)
            If MeasurementMetricUpdatedEvent IsNot Nothing Then
                Dim xx As Integer = ((Message.Parameters(0) - 48) * 16) + (Message.Parameters(1) - 48)

                Dim Value As Integer = CInt(xx * xx / 512)
                RaiseEvent MeasurementMetricUpdated(Me, New MeasurementMetricUpdatedEventArgs(MeasurementMetricType.Drive, Value.ToString & "W"))
            End If
        End Sub

        Private Sub HandleMessageMeasurementFrequency(Message As ACOMMessage)
            If MeasurementMetricUpdatedEvent IsNot Nothing Then
                Dim xx As Integer = ((Message.Parameters(0) - 48) * 4096) + ((Message.Parameters(1) - 48) * 256) + ((Message.Parameters(2) - 48) * 16) + (Message.Parameters(3) - 48)
                Dim Value As Integer = xx * 2
                RaiseEvent MeasurementMetricUpdated(Me, New MeasurementMetricUpdatedEventArgs(MeasurementMetricType.Frequency, Value.ToString("0000") & "kHz"))
            End If
        End Sub

        Private Sub HandleMessageMeasurementForwardPower(Message As ACOMMessage)
            If MeasurementMetricUpdatedEvent IsNot Nothing Then
                Dim xx As Integer = ((Message.Parameters(0) - 48) * 16) + (Message.Parameters(1) - 48)
                Dim Value As Double = (xx * xx / 16) / 1000
                RaiseEvent MeasurementMetricUpdated(Me, New MeasurementMetricUpdatedEventArgs(MeasurementMetricType.ForwardPower, Value.ToString("0.00") & "kW"))
            End If
        End Sub

        Private Sub HandleMessageMeasurementFilamentVoltage(Message As ACOMMessage)
            If MeasurementMetricUpdatedEvent IsNot Nothing Then
                Dim xx As Integer = ((Message.Parameters(0) - 48) * 16) + (Message.Parameters(1) - 48)
                Dim Value As Double = xx / 16
                RaiseEvent MeasurementMetricUpdated(Me, New MeasurementMetricUpdatedEventArgs(MeasurementMetricType.FilamentVoltage, Value.ToString("0.0") & "V"))
            End If
        End Sub

        Private Sub HandleMessageMeasurementPowerGain(Message As ACOMMessage)
            If MeasurementMetricUpdatedEvent IsNot Nothing Then
                Dim xx As Integer = ((Message.Parameters(0) - 48) * 16) + (Message.Parameters(1) - 48)
                Dim yy As Integer = ((Message.Parameters(2) - 48) * 16) + (Message.Parameters(3) - 48)
                Dim OutputValue As String = ""
                If yy = 0 Then
                    OutputValue = "----"
                Else
                    Dim Value As Double = 10 * Math.Log10(xx * xx / yy / yy * 32)
                    OutputValue = Value.ToString("0.0") & "dB"
                End If
                RaiseEvent MeasurementMetricUpdated(Me, New MeasurementMetricUpdatedEventArgs(MeasurementMetricType.PowerGain, OutputValue))
            End If
        End Sub

        Private Sub HandleMessageMeasurementHV(Message As ACOMMessage)
            If MeasurementMetricUpdatedEvent IsNot Nothing Then
                Dim xx As Integer = ((Message.Parameters(0) - 48) * 16) + (Message.Parameters(1) - 48)
                Dim Value As Double = (xx * 16) / 1000
                RaiseEvent MeasurementMetricUpdated(Me, New MeasurementMetricUpdatedEventArgs(MeasurementMetricType.HV, Value.ToString("0.00") & "kV"))
            End If
        End Sub

        Private Sub HandleMessageMeasurementIFFrontTube(Message As ACOMMessage)
            If MeasurementMetricUpdatedEvent IsNot Nothing Then
                Dim xx As Integer = ((Message.Parameters(0) - 48) * 16) + (Message.Parameters(1) - 48)
                Dim Value As Double = xx / 16
                RaiseEvent MeasurementMetricUpdated(Me, New MeasurementMetricUpdatedEventArgs(MeasurementMetricType.IFFrontTube, Value.ToString("0.0") & "A"))
            End If
        End Sub

        Private Sub HandleMessageMeasurementIFRearTube(Message As ACOMMessage)
            If MeasurementMetricUpdatedEvent IsNot Nothing Then
                Dim xx As Integer = ((Message.Parameters(0) - 48) * 16) + (Message.Parameters(1) - 48)
                Dim Value As Double = xx / 16
                RaiseEvent MeasurementMetricUpdated(Me, New MeasurementMetricUpdatedEventArgs(MeasurementMetricType.IFRearTube, Value.ToString("0.0") & "A"))
            End If
        End Sub

        Private Sub HandleMessageMeasurementGridCurrent(Message As ACOMMessage)
            If MeasurementMetricUpdatedEvent IsNot Nothing Then
                Dim xx As Integer = ((Message.Parameters(0) - 48) * 16) + (Message.Parameters(1) - 48)
                Dim Value As Double = xx / 10
                RaiseEvent MeasurementMetricUpdated(Me, New MeasurementMetricUpdatedEventArgs(MeasurementMetricType.GridCurrent, Value.ToString("0.0") & "mA"))
            End If
        End Sub

        Private Sub HandleMessageMeasurementPlateCurrent(Message As ACOMMessage)
            If MeasurementMetricUpdatedEvent IsNot Nothing Then
                Dim xx As Integer = ((Message.Parameters(0) - 48) * 16) + (Message.Parameters(1) - 48)
                Dim Value As Double = xx * 10
                RaiseEvent MeasurementMetricUpdated(Me, New MeasurementMetricUpdatedEventArgs(MeasurementMetricType.PlateCurrent, Value.ToString("0.00") & "mA"))
            End If
        End Sub

        Private Sub HandleMessageMeasurementScreenCurrent(Message As ACOMMessage)
            If MeasurementMetricUpdatedEvent IsNot Nothing Then
                Dim xx As Integer = ((Message.Parameters(0) - 48) * 16) + (Message.Parameters(1) - 48)
                Dim Value As Integer = xx
                RaiseEvent MeasurementMetricUpdated(Me, New MeasurementMetricUpdatedEventArgs(MeasurementMetricType.ScreenCurrent, Value.ToString & "mA"))
            End If
        End Sub

        Private Sub HandleMessageMeasurementMainsVoltage(Message As ACOMMessage)
            If MeasurementMetricUpdatedEvent IsNot Nothing Then
                Dim xx As Integer = ((Message.Parameters(0) - 48) * 16) + (Message.Parameters(1) - 48)
                Dim Value As Integer = CInt(xx * 10 / 8)
                RaiseEvent MeasurementMetricUpdated(Me, New MeasurementMetricUpdatedEventArgs(MeasurementMetricType.MainsVoltage, Value.ToString() & "V"))
            End If
        End Sub

        Private Sub HandleMessageMeasurementPlateRFVoltage(Message As ACOMMessage)
            If MeasurementMetricUpdatedEvent IsNot Nothing Then
                Dim xx As Integer = ((Message.Parameters(0) - 48) * 16) + (Message.Parameters(1) - 48)
                Dim Value As Double = (xx * 12) / 1000
                RaiseEvent MeasurementMetricUpdated(Me, New MeasurementMetricUpdatedEventArgs(MeasurementMetricType.PlateRFVoltage, Value.ToString("0.00") & "kV"))
            End If
        End Sub

        Private Sub HandleMessageMeasurementReflectedPower(Message As ACOMMessage)
            If MeasurementMetricUpdatedEvent IsNot Nothing Then
                Dim xx As Integer = ((Message.Parameters(0) - 48) * 16) + (Message.Parameters(1) - 48)
                Dim Value As Integer = CInt(xx * xx / 100)
                RaiseEvent MeasurementMetricUpdated(Me, New MeasurementMetricUpdatedEventArgs(MeasurementMetricType.ReflectedPower, Value.ToString & "W"))
            End If
        End Sub

        Private Sub HandleMessageMeasurementScreenVoltage(Message As ACOMMessage)
            If MeasurementMetricUpdatedEvent IsNot Nothing Then
                Dim xx As Integer = ((Message.Parameters(0) - 48) * 16) + (Message.Parameters(1) - 48)
                Dim Value As Integer = xx * 2
                RaiseEvent MeasurementMetricUpdated(Me, New MeasurementMetricUpdatedEventArgs(MeasurementMetricType.ScreenVoltage, Value.ToString & "V"))
            End If
        End Sub

        Private Sub HandleMessageMeasurementFrontTubeTemp(Message As ACOMMessage)
            If MeasurementMetricUpdatedEvent IsNot Nothing Then
                Dim xx As Integer = ((Message.Parameters(0) - 48) * 16) + (Message.Parameters(1) - 48)
                Dim Value As Integer = (xx - 136) * 2
                RaiseEvent MeasurementMetricUpdated(Me, New MeasurementMetricUpdatedEventArgs(MeasurementMetricType.FrontTubeTemp, Value.ToString & "£C"))
            End If
        End Sub

        Private Sub HandleMessageMeasurementRearTubeTemp(Message As ACOMMessage)
            If MeasurementMetricUpdatedEvent IsNot Nothing Then
                Dim xx As Integer = ((Message.Parameters(0) - 48) * 16) + (Message.Parameters(1) - 48)
                Dim Value As Integer = (xx - 136) * 2
                RaiseEvent MeasurementMetricUpdated(Me, New MeasurementMetricUpdatedEventArgs(MeasurementMetricType.RearTubeTemp, Value.ToString & "£C"))
            End If
        End Sub

        Private Sub HandleMessageMeasurementVSWR(Message As ACOMMessage)
            If MeasurementMetricUpdatedEvent IsNot Nothing Then
                Dim xx As Integer = ((Message.Parameters(0) - 48) * 16) + (Message.Parameters(1) - 48)
                Dim yy As Integer = ((Message.Parameters(2) - 48) * 16) + (Message.Parameters(3) - 48)

                Dim OutputValue As String = ""
                If xx = 0 And yy = 0 Then
                    OutputValue = "----"
                Else
                    Dim Value As Double = (2.5 * xx + yy) / (2.5 * xx - yy)
                    If Value > 9.8 Then
                        OutputValue = "Too High"
                    Else
                        OutputValue = Value.ToString("0.00")
                    End If
                End If
                RaiseEvent MeasurementMetricUpdated(Me, New MeasurementMetricUpdatedEventArgs(MeasurementMetricType.VSWR, OutputValue))
            End If
        End Sub

        Private Sub HandleMessageRCUEnteredMeasureMode()
            If RCUIsMeasuringEvent IsNot Nothing Then
                RaiseEvent RCUIsMeasuring(Me, New EventArgs)
            End If
        End Sub

        Private Sub HandleMessageStandbyModeOn()
            If StandbyModeOnEvent IsNot Nothing Then
                RaiseEvent StandbyModeOn(Me, New EventArgs)
            End If
        End Sub

        Private Sub HandleMessageOperateModeOn()
            If OperateModeOnEvent IsNot Nothing Then
                RaiseEvent OperateModeOn(Me, New EventArgs)
            End If
        End Sub

        Private Sub HandleMessagePowerOffComplete()
            If PowerOffCompleteEvent IsNot Nothing Then
                RaiseEvent PowerOffComplete(Me, New EventArgs)
            End If
        End Sub

        Private Sub HandleMessagePowerOffCoolingTubes()
            If PowerOffCoolingTubesEvent IsNot Nothing Then
                RaiseEvent PowerOffCoolingTubes(Me, New EventArgs)
            End If
        End Sub

        Private Sub HandleMessageHVOn()
            If HVOnExecutedEvent IsNot Nothing Then
                RaiseEvent HVOnExecuted(Me, New EventArgs)
            End If
        End Sub

        Private Sub HandleMessageBroadcastID(ByVal Message As ACOMMessage)
            'Are we using autodetection and are we waiting to discover the ACOM2000A address
            If m_UseAutoDetection And Not m_ACOM2000Detected Then
                If Message.SourceAddress >= Constants.LOWEST_AMPLIFIER_ADDRESS And Message.SourceAddress <= Constants.HIGHEST_AMPLIFIER_ADDRESS Then
                    'A Valid ACOM2000 Network address has been detected
                    m_TimeoutTimer.Stop()
                    m_ACOMNetworkACOM2000AAddress = Message.SourceAddress
                    m_ACOM2000Detected = True
                    If ACOM2000ADetectedEvent IsNot Nothing Then
                        RaiseEvent ACOM2000ADetected(Me, New ACOM2000ADetectedEventArgs(Message.SourceAddress))
                    End If
                End If
            End If
        End Sub

        Private Sub HandleMessageReflectedPowerLED(ByVal Message As ACOMMessage)
            If ReflectedPowerLedUpdatedEvent IsNot Nothing Then
                Dim Args As New PowerLedEventArgs(Message.Parameters(0) - Constants.REFLECTED_POWER_LED_MESSAGE_LOWESTVALUE)
                If ReflectedPowerLedUpdatedEvent IsNot Nothing Then
                    RaiseEvent ReflectedPowerLedUpdated(Me, Args)
                End If
            End If
        End Sub

        Private Sub HandleMessageForwardPowerLED(ByVal Message As ACOMMessage)
            If ForwardPowerLedUpdatedEvent IsNot Nothing Then
                Dim Args As New PowerLedEventArgs(Message.Parameters(0) - Constants.FORWARD_POWER_LED_MESSAGE_LOWESTVALUE)
                If ForwardPowerLedUpdatedEvent IsNot Nothing Then
                    RaiseEvent ForwardPowerLedUpdated(Me, Args)
                End If
            End If
        End Sub

        Private Sub HandleMessageCurrentSegmentInfo(ByVal Message As ACOMMessage)

            If BandFrequencyChangedEvent IsNot Nothing Then
                Dim BandSegmentID As Integer = ((Message.MessageData(4) - 48) * 16) + (Message.MessageData(5) - 48)
                Dim Segment As BandSegment = BandSegment.GetSegment(BandSegmentID)
                Dim AntennaNumber As Integer = Message.MessageData(6) - 48
                Dim USRMode As Boolean = (Message.MessageData(7) - 48) = 1
                Dim Band As FrequencyBand = CType(Message.MessageData(8) - 48, FrequencyBand)

                RaiseEvent BandFrequencyChanged(Me, New BandFrequencyEventArgs(Segment, AntennaNumber, USRMode, Band))
            End If

        End Sub

        Private Sub HandleMessageAirTemperature(ByVal Message As ACOMMessage)

            Dim NumberOfBars As Integer = Message.Parameters(0) - 48
            If NumberOfBars <= 13 Then
                If AirTemperatureChangedEvent IsNot Nothing Then
                    RaiseEvent AirTemperatureChanged(Me, New AirTemperatureEventArgs(NumberOfBars))
                End If
            Else
                Throw New AcomMessageException("Air Temperature message received with a number of bars value exceeding 13")
            End If

        End Sub

        Private Sub HandleMessageBANDMotorPosition(ByVal Message As ACOMMessage)

            'Command Length should be 7
            If Not Message.MessageData.Length = 7 Then
                Throw New AcomMessageException("Invalid Message length for command:" & Message.MessageType)
            End If

            'Only fire the event if it is subscribed to
            If BandMotorPositionUpdatedEvent IsNot Nothing Then
                'Get the Sensor setting
                Dim SensorFlag As String = Chr(Message.Parameters(3))
                Dim Sensor As MotorSensorState
                If SensorFlag = "L" Then
                    Sensor = MotorSensorState.Light
                ElseIf SensorFlag = "D" Then
                    Sensor = MotorSensorState.Dark
                Else
                    Throw New AcomMessageException("Unknown sensor setting received from response message A, sensor flag should be either L or D but the value " & SensorFlag & " was received")
                End If

                'Get the position 
                Dim PositionString As String = Chr(Message.Parameters(0)) & Chr(Message.Parameters(1)) & Chr(Message.Parameters(2))
                Dim Position As Integer = CInt(PositionString)

                RaiseEvent BandMotorPositionUpdated(Me, New MotorPositionEventArgs(Position, Sensor))
            End If

        End Sub

        Private Sub HandleMessageLOADMotorPosition(ByVal Message As ACOMMessage)

            'Command Length should be 7
            If Not Message.MessageData.Length = 7 Then
                Throw New AcomMessageException("Invalid Message length for command:" & Message.MessageType)
            End If

            'Only fire the event if it is subscribed to
            If LoadMotorPositionUpdatedEvent IsNot Nothing Then
                'Get the Sensor setting
                Dim SensorFlag As String = Chr(Message.MessageData(6))
                Dim Sensor As MotorSensorState
                If SensorFlag = "L" Then
                    Sensor = MotorSensorState.Light
                ElseIf SensorFlag = "D" Then
                    Sensor = MotorSensorState.Dark
                Else
                    Throw New AcomMessageException("Unknown sensor setting received from response message B, sensor flag should be either L or D but the value " & SensorFlag & " was received")
                End If

                'Get the position 
                Dim PositionString As String = Chr(Message.MessageData(3)) & Chr(Message.MessageData(4)) & Chr(Message.MessageData(5))
                Dim Position As Integer = CInt(PositionString)

                RaiseEvent LoadMotorPositionUpdated(Me, New MotorPositionEventArgs(Position, Sensor))
            End If

        End Sub

        Private Sub HandleMessageTUNEMotorPosition(ByVal Message As ACOMMessage)

            'Command Length should be 7
            If Not Message.MessageData.Length = 7 Then
                Throw New AcomMessageException("Invalid Message length for command:" & Message.MessageType)
            End If

            'Only fire the event if it is subscribed to
            If TuneMotorPositionUpdatedEvent IsNot Nothing Then
                'Get the Sensor setting
                Dim SensorFlag As String = Chr(Message.MessageData(6))
                Dim Sensor As MotorSensorState
                If SensorFlag = "L" Then
                    Sensor = MotorSensorState.Light
                ElseIf SensorFlag = "D" Then
                    Sensor = MotorSensorState.Dark
                Else
                    Throw New AcomMessageException("Unknown sensor setting received from response message C, sensor flag should be either L or D but the value " & SensorFlag & " was received")
                End If

                'Get the position 
                Dim PositionString As String = Chr(Message.MessageData(3)) & Chr(Message.MessageData(4)) & Chr(Message.MessageData(5))
                Dim Position As Integer = CInt(PositionString)

                RaiseEvent TuneMotorPositionUpdated(Me, New MotorPositionEventArgs(Position, Sensor))
            End If

        End Sub

        Private Sub HandleMessageLEDStatus(ByVal Message As ACOMMessage)

            'Uses the Lower 4 Bytes only to signify status 

            If LEDStatusUpdateEvent IsNot Nothing Then
                'Protection LED
                Dim ProtectionLED As LedStatus = LedStatus.Off
                If CBool(Message.MessageData(3) And &H4) Then
                    ProtectionLED = LedStatus.Blinking
                ElseIf CBool(Message.MessageData(3) And &HC) Then
                    ProtectionLED = LedStatus.On
                End If

                'Header LED
                Dim HeaterLED As LedStatus = LedStatus.Off
                If CBool(Message.MessageData(3) And &H1) Then
                    HeaterLED = LedStatus.Blinking
                ElseIf CBool(Message.MessageData(3) And &H3) Then
                    HeaterLED = LedStatus.On
                End If

                'Standby LED
                Dim StandByLED As LedStatus = LedStatus.Off
                If Not CBool(Message.MessageData(4) And &H1) Then
                    StandByLED = LedStatus.On
                End If

                'Operate LED
                Dim OperateLED As LedStatus = LedStatus.Off
                If CBool(Message.MessageData(4) And &H1) Then
                    OperateLED = LedStatus.On
                End If

                'Drive LED
                Dim DriveLED As LedStatus = LedStatus.Off
                If CBool(Message.MessageData(4) And &H2) Then
                    DriveLED = LedStatus.On
                End If

                'Plate LED
                Dim PlateLED As LedStatus = LedStatus.Off
                If CBool(Message.MessageData(4) And &H4) Then
                    PlateLED = LedStatus.On
                End If

                RaiseEvent LEDStatusUpdate(Me, New LEDStatusEventArgs(ProtectionLED, HeaterLED, StandByLED, OperateLED, DriveLED, PlateLED))
            End If

        End Sub

        Private Sub HandleMessagePowerOnExecuted()
            If PowerOnExecutedEvent IsNot Nothing Then
                RaiseEvent PowerOnExecuted(Me, New EventArgs)
            End If
        End Sub

        Private Sub HandleMessagePowerOffExecuted()
            If PowerOffExecutedEvent IsNot Nothing Then
                RaiseEvent PowerOffExecuted(Me, New EventArgs)
            End If
        End Sub

        Private Sub HandleMessageEEPROMContents(ByVal Message As ACOMMessage)

            'TODO: This needs completing
            'Please note most of this routine is commented out until it's completed to avoid the code analysis generating unneccesary warnings

            'Get the EEPROM Segment Number
            Dim SegmentNumber As Integer = Message.MessageData(4) - 48
            If SegmentNumber < 0 Or SegmentNumber > 7 Then
                Throw New AcomMessageException("Unexpected Segment Number from response message G3, reported segment " & SegmentNumber.ToString & " when the value should be between 0 and 7")
            End If

            Select Case SegmentNumber
                Case 0
                    '        If AmplifierInfoReceivedEvent IsNot Nothing Then
                    '            Dim AmplifierSerial As String = Chr(Message.MessageData(5)) & Chr(Message.MessageData(6)) & Chr(Message.MessageData(7)) & Chr(Message.MessageData(8)) & Chr(Message.MessageData(9)) & Chr(Message.MessageData(10))
                    '            Dim RCUSerial As String = Chr(Message.MessageData(11)) & Chr(Message.MessageData(12)) & Chr(Message.MessageData(13)) & Chr(Message.MessageData(14)) & Chr(Message.MessageData(15)) & Chr(Message.MessageData(16))
                    '            Dim FrontTubeSerial As String = Chr(Message.MessageData(17)) & Chr(Message.MessageData(18)) & Chr(Message.MessageData(19)) & Chr(Message.MessageData(20)) & Chr(Message.MessageData(21)) & Chr(Message.MessageData(22))
                    '            Dim RearTubeSerial As String = Chr(Message.MessageData(23)) & Chr(Message.MessageData(24)) & Chr(Message.MessageData(25)) & Chr(Message.MessageData(26)) & Chr(Message.MessageData(27)) & Chr(Message.MessageData(28))
                    '            Dim LicenceStatus As String = Chr(Message.MessageData(29))
                    '            Dim PowerOnTimeSeconds As Integer = CInt("&H" & Hex(Message.MessageData(30) - 48) & Hex(Message.MessageData(31) - 48) & Hex(Message.MessageData(32) - 48) & Hex(Message.MessageData(33) - 48) & Hex(Message.MessageData(34) - 48) & Hex(Message.MessageData(35) - 48) & Hex(Message.MessageData(36) - 48))

                    '            RaiseEvent AmplifierInfoReceived(Me, New AmplifierInfoEventArgs(AmplifierSerial, RCUSerial, FrontTubeSerial, RearTubeSerial, LicenceStatus, PowerOnTimeSeconds))
                    '        End If
                Case 1

                    '        Dim RCUFirmwareRevision As String = Chr(Message.MessageData(5))
                    '        Dim CPUFirmwareRevision As String = Chr(Message.MessageData(6))
                    '        Dim EEPROM As String = Chr(Message.MessageData(7)) & Chr(Message.MessageData(8))
                    '        Dim Callsign As String = _
                    '            Chr(((Message.MessageData(9) - 48) * 16) + (Message.MessageData(10) - 48)) & _
                    '            Chr(((Message.MessageData(11) - 48) * 16) + (Message.MessageData(12) - 48)) & _
                    '            Chr(((Message.MessageData(13) - 48) * 16) + (Message.MessageData(14) - 48)) & _
                    '            Chr(((Message.MessageData(15) - 48) * 16) + (Message.MessageData(16) - 48)) & _
                    '            Chr(((Message.MessageData(17) - 48) * 16) + (Message.MessageData(18) - 48)) & _
                    '            Chr(((Message.MessageData(19) - 48) * 16) + (Message.MessageData(20) - 48)) & _
                    '            Chr(((Message.MessageData(21) - 48) * 16) + (Message.MessageData(22) - 48)) & _
                    '            Chr(((Message.MessageData(23) - 48) * 16) + (Message.MessageData(24) - 48)) & _
                    '            Chr(((Message.MessageData(25) - 48) * 16) + (Message.MessageData(26) - 48))

                    '        'TODO: Need to strip unused Characters from the callsign 

                    '        Dim Key As String = Chr(Message.MessageData(27))


                    '        Dim ErrorCode As String = Chr(Message.MessageData(28)) & Chr(Message.MessageData(29))
                    '        Dim ErrorParam As String = Chr(Message.MessageData(30)) & Chr(Message.MessageData(31))
                    '        Dim Antenna As String = Chr(Message.MessageData(32))


                    '        'Dim Time As Integer = CInt("&H" & Hex(CurrentCommand(31) - 48) & Hex(CurrentCommand(32) - 48) & Hex(CurrentCommand(33) - 48) & Hex(CurrentCommand(34) - 48) & Hex(CurrentCommand(35) - 48) & Hex(CurrentCommand(36) - 48) & Hex(CurrentCommand(37) - 48))
                    '        'Dim Segment As String


                Case 2, 3, 4, 5, 6

                    '        If UnknownMessageEvent IsNot Nothing Then
                    '            RaiseEvent UnknownMessage(Me, New UnknownMessageEventArgs("UNKNOWN EEPROM CONTENTS"))
                    '        End If

                Case 7

                    '        'CurrentCommand(5) - DOES NOT APPEAR TO BE USED
                    '        'CurrentCommand(6) - DOES NOT APPEAR TO BE USED
                    '        Dim MainsVoltageSelection As String = Chr(Message.MessageData(7))
                    '        'CurrentCommand(8) - DOES NOT APPEAR TO BE USED
                    '        Dim AccessCode As String = _
                    '            Chr(((Message.MessageData(9) - 48) * 16) + (Message.MessageData(10) - 48)) & _
                    '            Chr(((Message.MessageData(11) - 48) * 16) + (Message.MessageData(12) - 48)) & _
                    '            Chr(((Message.MessageData(13) - 48) * 16) + (Message.MessageData(14) - 48)) & _
                    '            Chr(((Message.MessageData(15) - 48) * 16) + (Message.MessageData(16) - 48)) & _
                    '            Chr(((Message.MessageData(17) - 48) * 16) + (Message.MessageData(18) - 48)) & _
                    '            Chr(((Message.MessageData(19) - 48) * 16) + (Message.MessageData(20) - 48))

                    '        Dim LocalNetworkAddress As Integer = ((Message.MessageData(21) - 48) * 16) + (Message.MessageData(22) - 48)

                    '        Dim AutoAntennaChange As String = (((Message.MessageData(23) - 48) * 16) + (Message.MessageData(24) - 48)).ToString

                    '        'CurrentCommand(25) -> CurrentCommand(36) - DOES NOT APPEAR TO BE USED



            End Select

        End Sub

        Private Sub HandleMessageAmplifierError(ByVal Message As ACOMMessage)

            If AmplifierErrorEvent IsNot Nothing Then
                Dim ErrorCode As Integer = ((Message.Parameters(0) - 48) * 16) + (Message.Parameters(1) - 48)
                Dim RAWParameter As Integer = 0
                If Not Message.Parameters(2) = 0 And Not Message.Parameters(3) = 0 Then
                    RAWParameter = ((Message.Parameters(2) - 48) * 16) + (Message.Parameters(3) - 48)
                End If

                Select Case ErrorCode
                    Case 1 '= COVER INTERLOCK OPEN
                        RaiseEvent AmplifierError(Me, New ErrorEventArgs("COVER INTERLOCK OPEN", ErrorParameterType.None, ""))
                    Case 2 '= +5V TOO HIGH:                                  V
                        'TODO: Need to determine the calculation for the parameter
                        RaiseEvent AmplifierError(Me, New ErrorEventArgs("+5V TOO HIGH", ErrorParameterType.None, ""))
                    Case 3 '= +12V TOO HIGH:                                 V
                        'TODO: Need to determine the calculation for the parameter
                        RaiseEvent AmplifierError(Me, New ErrorEventArgs("+12V TOO HIGH", ErrorParameterType.None, ""))
                    Case 4 '= -12V TOO HIGH:                                 V
                        'TODO: Need to determine the calculation for the parameter
                        RaiseEvent AmplifierError(Me, New ErrorEventArgs("-12V TOO HIGH", ErrorParameterType.None, ""))
                    Case 5 '= LINE VOLTAGE TOO HIGH:                         V
                        'TODO: Need to determine the calculation for the parameter
                        RaiseEvent AmplifierError(Me, New ErrorEventArgs("LINE VOLTAGE|TOO HIGH", ErrorParameterType.None, ""))
                    Case 7 '= SCREEN VOLTAGE ON BEFORE TIMEOUT OVER:         V
                        'TODO: Need to determine the calculation for the parameter
                        RaiseEvent AmplifierError(Me, New ErrorEventArgs("SCREEN VOLTAGE ON|BEFORE TIMEOUT OVER", ErrorParameterType.None, ""))
                    Case 8 '= IG2 PRESENT: IT SHOULD BE ZERO:                mA
                        'TODO: Need to determine the calculation for the parameter
                        RaiseEvent AmplifierError(Me, New ErrorEventArgs("IG2 PRESENT|IT SHOULD BE ZERO", ErrorParameterType.None, ""))
                    Case 9 '= IG1 PRESENT: IT SHOULD BE ZERO:                mA
                        'TODO: Need to determine the calculation for the parameter
                        RaiseEvent AmplifierError(Me, New ErrorEventArgs("IG1 PRESENT|IT SHOULD BE ZERO", ErrorParameterType.None, ""))
                    Case 10 '= Ip PRESENT: IT SHOULD BE ZERO:                 mA
                        'TODO: Need to determine the calculation for the parameter
                        RaiseEvent AmplifierError(Me, New ErrorEventArgs("Ip PRESENT|IT SHOULD BE ZERO", ErrorParameterType.None, ""))
                    Case 13 '= +48V TOO HIGH:                                 V
                        'TODO: Need to determine the calculation for the parameter
                        RaiseEvent AmplifierError(Me, New ErrorEventArgs("+48V TOO HIGH", ErrorParameterType.None, ""))
                    Case 14 '= ANTENNA RELAY CLOSED: IT SHOULD BE OPEN
                        RaiseEvent AmplifierError(Me, New ErrorEventArgs("ANTENNA RELAY CLOSED|IT SHOULD BE OPEN", ErrorParameterType.None, ""))
                    Case 15 '= INPUT RELAY CLOSED: IT SHOULD BE OPEN
                        RaiseEvent AmplifierError(Me, New ErrorEventArgs("INPUT RELAY CLOSED|IT SHOULD BE OPEN", ErrorParameterType.None, ""))
                    Case 16 '= QSK BREAK in FAULT: PROCESSOR CONFLICT
                        RaiseEvent AmplifierError(Me, New ErrorEventArgs("QSK BREAK in FAULT|PROCESSOR CONFLICT", ErrorParameterType.None, ""))
                    Case 17 '= RF PLATE PRESENT: IT SHOULD BE ZERO:           V
                        'TODO: Need to determine the calculation for the parameter
                        RaiseEvent AmplifierError(Me, New ErrorEventArgs("RF PLATE PRESENT|IT SHOULD BE ZERO", ErrorParameterType.None, ""))
                    Case 18 '= RF GRID POWER PRESENT:IT SHOULD BE ZERO:       W
                        'TODO: Need to determine the calculation for the parameter
                        RaiseEvent AmplifierError(Me, New ErrorEventArgs("RF GRID POWER PRESENT|IT SHOULD BE ZERO", ErrorParameterType.None, ""))
                    Case 19 '= HEATERS ON BEFORE TIMEOUT STARTED
                        RaiseEvent AmplifierError(Me, New ErrorEventArgs("HEATERS ON BEFORE|TIMEOUT STARTED", ErrorParameterType.None, ""))
                    Case 21 '= REAR TUBE EXHAUST TEMP TOO HIGH:               oC
                        Dim Parameter As Integer = 0
                        Parameter = (RAWParameter - 136) * 2
                        RaiseEvent AmplifierError(Me, New ErrorEventArgs("REAR TUBE EXHAUST|TEMP TOO HIGH $var$", ErrorParameterType.DegC, Parameter.ToString & "£C"))
                    Case 22 '= FRONT TUBE EXHAUST TEMP TOO HIGH:              oC
                        Dim Parameter As Integer = 0
                        Parameter = (RAWParameter - 136) * 2
                        RaiseEvent AmplifierError(Me, New ErrorEventArgs("FRONT TUBE EXHAUST|TEMP TOO HIGH $var$", ErrorParameterType.DegC, Parameter.ToString & "£C"))
                    Case 23 '= HV TOO LOW AT POWER ON:                        V
                        'TODO: Need to determine the calculation for the parameter
                        RaiseEvent AmplifierError(Me, New ErrorEventArgs("HV TOO LOW|AT POWER ON", ErrorParameterType.None, ""))
                    Case 24 '= BIAS TOO LOW AT POWER ON:                      V
                        'TODO: Need to determine the calculation for the parameter
                        RaiseEvent AmplifierError(Me, New ErrorEventArgs("BIAS TOO LOW|AT POWER ON", ErrorParameterType.None, ""))
                    Case 26 '= G2: CURRENT TOO HIGH:                          mA
                        'TODO: Need to determine the calculation for the parameter
                        RaiseEvent AmplifierError(Me, New ErrorEventArgs("G2|CURRENT TOO HIGH", ErrorParameterType.None, ""))
                    Case 27 '= G1: EXCESSIVE GRID CURRENT:                    mA
                        'TODO: Need to determine the calculation for the parameter
                        RaiseEvent AmplifierError(Me, New ErrorEventArgs("G1|EXCESSIVE GRID CURRENT", ErrorParameterType.None, ""))
                    Case 30 '= Ip PRESENT: SHOULD BE ZERO:                    mA
                        'TODO: Need to determine the calculation for the parameter
                        RaiseEvent AmplifierError(Me, New ErrorEventArgs("Ip PRESENT|SHOULD BE ZERO", ErrorParameterType.None, ""))
                    Case 31 '= HEATER VOLTAGE TOO HIGH:                       V
                        'TODO: Need to determine the calculation for the parameter
                        RaiseEvent AmplifierError(Me, New ErrorEventArgs("HEATER VOLTAGE|TOO HIGH", ErrorParameterType.None, ""))
                    Case 33 '= HEATER CURRENT TOO HIGH:                       A
                        'TODO: Need to determine the calculation for the parameter
                        RaiseEvent AmplifierError(Me, New ErrorEventArgs("HEATER CURRENT|TOO HIGH", ErrorParameterType.None, ""))
                    Case 35 '= BIAS VOLTAGE TOO LOW:                          V
                        'TODO: Need to determine the calculation for the parameter
                        RaiseEvent AmplifierError(Me, New ErrorEventArgs("BIAS VOLTAGE TOO LOW", ErrorParameterType.None, ""))
                    Case 36 '= G2 CONTROL CIRCUIT MALFUNCTION
                        RaiseEvent AmplifierError(Me, New ErrorEventArgs("G2 CONTROL|CIRCUIT MALFUNCTION", ErrorParameterType.None, ""))
                    Case 37 '= AUTOMATIC PROTECTION:DRIVE POWER REMOVED
                        RaiseEvent AmplifierError(Me, New ErrorEventArgs("AUTOMATIC PROTECTION|DRIVE POWER REMOVED", ErrorParameterType.None, ""))
                    Case 38 '= REMOVE AND REDUCE DRIVE POWER
                        RaiseEvent AmplifierError(Me, New ErrorEventArgs("REMOVE AND REDUCE|DRIVE POWER", ErrorParameterType.None, ""))
                    Case 39 '= HIGH VOLTAGE TOO LOW:                          kV
                        'TODO: Need to determine the calculation for the parameter
                        RaiseEvent AmplifierError(Me, New ErrorEventArgs("HIGH VOLTAGE TOO LOW", ErrorParameterType.None, ""))
                    Case 40 '= G2 VOLTAGE TOO LOW:                            V
                        'TODO: Need to determine the calculation for the parameter
                        RaiseEvent AmplifierError(Me, New ErrorEventArgs("G2 VOLTAGE TOO LOW", ErrorParameterType.None, ""))
                    Case 41 '= HIGH VOLTAGE TOO HIGH:                         kV
                        'TODO: Need to determine the calculation for the parameter
                        RaiseEvent AmplifierError(Me, New ErrorEventArgs("HIGH VOLTAGE|TOO HIGH", ErrorParameterType.None, ""))
                    Case 42 '= HEATER VOLTAGE TOO LOW:                        V
                        'TODO: Need to determine the calculation for the parameter
                        RaiseEvent AmplifierError(Me, New ErrorEventArgs("HEATER VOLTAGE|TOO LOW", ErrorParameterType.None, ""))
                    Case 43 '= HEATER CURRENT TOO LOW:                        A
                        'TODO: Need to determine the calculation for the parameter
                        RaiseEvent AmplifierError(Me, New ErrorEventArgs("HEATER CURRENT|TOO LOW", ErrorParameterType.None, ""))
                    Case 45 '= LOW AIRFLOW
                        RaiseEvent AmplifierError(Me, New ErrorEventArgs("LOW AIRFLOW", ErrorParameterType.None, ""))
                    Case 46 '= ANTENNA RELAY OPEN:IT SHOULD BE CLOSED
                        RaiseEvent AmplifierError(Me, New ErrorEventArgs("ANTENNA RELAY OPEN|IT SHOULD BE CLOSED", ErrorParameterType.None, ""))
                    Case 47 '= DRIVE POWER TOO HIGH:                          W
                        'TODO: Need to determine the calculation for the parameter
                        RaiseEvent AmplifierError(Me, New ErrorEventArgs("DRIVE POWER TOO HIGH", ErrorParameterType.None, ""))
                    Case 48 '= REFLECTED POWER TOO HIGH:                      W
                        Dim Parameter As Integer = 0
                        Parameter = CInt(Math.Floor((RAWParameter * RAWParameter) / 100))
                        RaiseEvent AmplifierError(Me, New ErrorEventArgs("REFLECTED POWER TOO|HIGH = $var$", ErrorParameterType.Watts, Parameter.ToString & "W"))
                    Case 49 '= EXCESSIVE PLATE CURRENT:                       mA
                        'TODO: Need to determine the calculation for the parameter
                        RaiseEvent AmplifierError(Me, New ErrorEventArgs("EXCESSIVE|PLATE CURRENT", ErrorParameterType.None, ""))
                    Case 50 '= EXCESSIVE G2 CURRENT:                          mA
                        'TODO: Need to determine the calculation for the parameter
                        RaiseEvent AmplifierError(Me, New ErrorEventArgs("EXCESSIVE|G2 CURRENT", ErrorParameterType.None, ""))
                    Case 54 '= ARC FAULT
                        RaiseEvent AmplifierError(Me, New ErrorEventArgs("ARC FAULT", ErrorParameterType.None, ""))
                    Case 55 '= DRIVE FREQUENCY OUT OF RANGE
                        RaiseEvent AmplifierError(Me, New ErrorEventArgs("DRIVE FREQUENCY|OUT OF RANGE", ErrorParameterType.None, ""))
                    Case 58 '= BIAS CONTROL CIRQUIT MALFUNCTION
                        RaiseEvent AmplifierError(Me, New ErrorEventArgs("BIAS CONTROL|CIRQUIT MALFUNCTION", ErrorParameterType.None, ""))
                    Case 59 '= BAND SWITCH SYSTEM MALFUNCTION
                        RaiseEvent AmplifierError(Me, New ErrorEventArgs("BAND SWITCH|SYSTEM MALFUNCTION", ErrorParameterType.None, ""))
                    Case 60 '= DETECTED RF POWER AT WRONG TIME
                        RaiseEvent AmplifierError(Me, New ErrorEventArgs("DETECTED RF POWER|AT WRONG TIME", ErrorParameterType.None, ""))
                    Case 61 '= ADC - OVERFLOW
                        RaiseEvent AmplifierError(Me, New ErrorEventArgs("ADC - OVERFLOW", ErrorParameterType.None, ""))
                    Case 62 '= MICROPROCESSOR CONFLICT
                        RaiseEvent AmplifierError(Me, New ErrorEventArgs("MICROPROCESSOR|CONFLICT", ErrorParameterType.None, ""))
                    Case 63 '= FREQUENCY VIOLATION
                        RaiseEvent AmplifierError(Me, New ErrorEventArgs("FREQUENCY VIOLATION", ErrorParameterType.None, ""))
                    Case 65 '= LOW GAIN
                        RaiseEvent AmplifierError(Me, New ErrorEventArgs("LOW GAIN", ErrorParameterType.None, ""))
                    Case 66 '= +5V TOO LOW:                                   V
                        'TODO: Need to determine the calculation for the parameter
                        RaiseEvent AmplifierError(Me, New ErrorEventArgs("+5V TOO LOW", ErrorParameterType.None, ""))
                    Case 67 '= +12V TOO LOW:                                  V
                        'TODO: Need to determine the calculation for the parameter
                        RaiseEvent AmplifierError(Me, New ErrorEventArgs("+12V TOO LOW", ErrorParameterType.None, ""))
                    Case 68 '= -12V TOO LOW:                                  V
                        'TODO: Need to determine the calculation for the parameter
                        RaiseEvent AmplifierError(Me, New ErrorEventArgs("-12V TOO LOW", ErrorParameterType.None, ""))
                    Case 69 '= LINE AC VOLTAGE TOO LOW:                       V
                        'TODO: Need to determine the calculation for the parameter
                        RaiseEvent AmplifierError(Me, New ErrorEventArgs("LINE AC VOLTAGE|TOO LOW", ErrorParameterType.None, ""))
                    Case 70 '= +48V TOO LOW:                                  V
                        'TODO: Need to determine the calculation for the parameter
                        RaiseEvent AmplifierError(Me, New ErrorEventArgs("+48V TOO LOW", ErrorParameterType.None, ""))
                    Case 71 '= G2 VOLTAGE TOO HIGH:                           V
                        'TODO: Need to determine the calculation for the parameter
                        RaiseEvent AmplifierError(Me, New ErrorEventArgs("G2 VOLTAGE TOO HIGH", ErrorParameterType.None, ""))
                    Case 72 '= AUTO PROTECTION: ARC FAULT 5 TIMES
                        RaiseEvent AmplifierError(Me, New ErrorEventArgs("AUTO PROTECTION|ARC FAULT 5 TIMES", ErrorParameterType.None, ""))
                    Case 73 '= TUNE CAPACITOR SYSTEM MALFUNCTION
                        RaiseEvent AmplifierError(Me, New ErrorEventArgs("TUNE CAPACITOR|SYSTEM MALFUNCTION", ErrorParameterType.None, ""))
                    Case 74 '= LOAD CAPACITOR SYSTEM MALFUNCTION
                        RaiseEvent AmplifierError(Me, New ErrorEventArgs("LOAD CAPACITOR|SYSTEM MALFUNCTION", ErrorParameterType.None, ""))
                    Case 75 '= MOTOR VOLTAGE TOO LOW:                         V
                        'TODO: Need to determine the calculation for the parameter
                        RaiseEvent AmplifierError(Me, New ErrorEventArgs("MOTOR VOLTAGE|TOO LOW", ErrorParameterType.None, ""))
                    Case 76 '= MOTOR VOLTAGE TOO HIGH:                        V
                        'TODO: Need to determine the calculation for the parameter
                        RaiseEvent AmplifierError(Me, New ErrorEventArgs("MOTOR VOLTAGE|TOO HIGH", ErrorParameterType.None, ""))
                    Case 77 '= +24V TOO LOW:                                  V
                        'TODO: Need to determine the calculation for the parameter
                        RaiseEvent AmplifierError(Me, New ErrorEventArgs("+24V TOO LOW", ErrorParameterType.None, ""))
                    Case 78 '= +24V TOO HIGH:                                 V
                        'TODO: Need to determine the calculation for the parameter
                        RaiseEvent AmplifierError(Me, New ErrorEventArgs("+24V TOO HIGH", ErrorParameterType.None, ""))
                    Case 80 '= ANTENNA CONTROL UNIT MALFUNCTION
                        RaiseEvent AmplifierError(Me, New ErrorEventArgs("ANTENNA CONTROL|UNIT MALFUNCTION", ErrorParameterType.None, ""))
                    Case Else
                        RaiseEvent AmplifierError(Me, New ErrorEventArgs("UNKNOWN ERROR|CODE " & ErrorCode.ToString(), ErrorParameterType.None, ""))
                End Select
            End If

        End Sub

#End Region

#End Region

#Region " Private Properties "

        ''' <summary>
        ''' True if the connection is ready to send a message, otherwise false
        ''' </summary>
        ''' <value></value>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Private ReadOnly Property ReadyToSendMessage As Boolean
            Get
                If m_RS232.IsOpen And m_ACOM2000Detected Then
                    Return True
                End If
                Return False
            End Get
        End Property

#End Region

#Region " Amplifier Commands "

        ''' <summary>
        ''' Performs a power on of the ACOM2000A
        ''' </summary>
        ''' <param name="Method"></param>
        ''' <remarks></remarks>
        Public Sub PerformRemotePowerOn(ByVal Method As RemotePowerOnSystem)
            m_WasConnectedBeforePowerON = m_RS232.IsOpen
            If m_WasConnectedBeforePowerON Then
                m_RS232.Disconnect()
            End If

            Dim RS232Parameters As New Framework.RS232.RS232PortParameters(1200, m_COMPort, False, False, IO.Ports.StopBits.One, 8, IO.Ports.Handshake.None, IO.Ports.Parity.None)
            m_RemotePowerOnRS232Connection = New RS232.RS232Port
            m_RemotePowerOnRS232Connection.Connect(RS232Parameters)

            Select Case Method
                Case RemotePowerOnSystem.DTR
                    m_RemotePowerOnRS232Connection.DtrEnable = True
                Case RemotePowerOnSystem.RTS
                    m_RemotePowerOnRS232Connection.RtsEnable = True
                Case RemotePowerOnSystem.RTSandDTR
                    m_RemotePowerOnRS232Connection.RtsEnable = True
                    m_RemotePowerOnRS232Connection.DtrEnable = True
            End Select

            m_PowerOnTimer.Start()

        End Sub

        ''' <summary>
        ''' Tells the amplifier to start measuring
        ''' </summary>
        ''' <param name="MetricA"></param>
        ''' <param name="MetricB"></param>
        ''' <remarks></remarks>
        Public Sub StartMeasurement(ByVal MetricA As MeasurementMetricType, ByVal MetricB As MeasurementMetricType)
            If ReadyToSendMessage Then
                SendMessage("M" & GetMeasurmentMetricCharacter(MetricA) & GetMeasurmentMetricCharacter(MetricB))
            End If
        End Sub

        ''' <summary>
        ''' Requests the amplifier return the current BAND Motor position
        ''' </summary>
        ''' <remarks></remarks>
        Public Sub GetBandMotorPosition()
            If ReadyToSendMessage Then
                SendMessage("A0")
            End If
        End Sub

        ''' <summary>
        ''' Steps up the BAND Motor position
        ''' </summary>
        ''' <remarks></remarks>
        Public Sub StepBandMotorUp()
            If ReadyToSendMessage Then
                SendMessage("A+")
            End If
        End Sub

        ''' <summary>
        ''' Steps down the BAND Motor position
        ''' </summary>
        ''' <remarks></remarks>
        Public Sub StepBandMotorDown()
            If ReadyToSendMessage Then
                SendMessage("A-")
            End If
        End Sub

        ''' <summary>
        ''' Requests the amplifier return the current LOAD Motor position
        ''' </summary>
        ''' <remarks></remarks>
        Public Sub GetLoadMotorPosition()
            If ReadyToSendMessage Then
                SendMessage("B0")
            End If
        End Sub

        ''' <summary>
        ''' Steps up the LOAD Motor position
        ''' </summary>
        ''' <remarks></remarks>
        Public Sub StepLoadMotorUp()
            If ReadyToSendMessage Then
                SendMessage("B+")
            End If
        End Sub

        ''' <summary>
        ''' Stops measuring mode
        ''' </summary>
        ''' <remarks></remarks>
        Public Sub StopMeasuring()
            If ReadyToSendMessage Then
                SendMessage("MM")
            End If
        End Sub

        ''' <summary>
        ''' Steps down the LOAD Motor position
        ''' </summary>
        ''' <remarks></remarks>
        Public Sub StepLoadMotorDown()
            If ReadyToSendMessage Then
                SendMessage("B-")
            End If
        End Sub

        ''' <summary>
        ''' Requests the amplifier return the current TUNE Motor position
        ''' </summary>
        ''' <remarks></remarks>
        Public Sub GetTuneMotorPosition()
            If ReadyToSendMessage Then
                SendMessage("C0")
            End If
        End Sub

        ''' <summary>
        ''' Steps up the TUNE Motor position
        ''' </summary>
        ''' <remarks></remarks>
        Public Sub StepTuneMotorUp()
            If ReadyToSendMessage Then
                SendMessage("C+")
            End If
        End Sub

        ''' <summary>
        ''' Steps down the TUNE Motor position
        ''' </summary>
        ''' <remarks></remarks>
        Public Sub StepTuneMotorDown()
            If ReadyToSendMessage Then
                SendMessage("C-")
            End If
        End Sub

        ''' <summary>
        ''' Turns off the amplifier
        ''' </summary>
        ''' <remarks></remarks>
        Public Sub TurnAmplifierOff()
            If ReadyToSendMessage Then
                SendMessage("0")
            End If
        End Sub

        ''' <summary>
        ''' 
        ''' </summary>
        ''' <remarks></remarks>
        Public Sub PressEscape()
            If ReadyToSendMessage Then
                SendMessage("K")
            End If
        End Sub

        ''' <summary>
        ''' Gets the specified EEPROM Memory page number
        ''' </summary>
        ''' <param name="PageNumber">The page number (0-7)</param>
        ''' <remarks></remarks>
        Public Sub GetEEPROMPage(ByVal PageNumber As Integer)
            If PageNumber < 0 Or PageNumber > 7 Then
                Throw New ArgumentOutOfRangeException("PageNumber", "PageNumber must be between 0 and 7")
            End If

            If ReadyToSendMessage Then
                SendMessage("G3" & PageNumber.ToString)
            End If
        End Sub

        ''' <summary>
        ''' Put the amplifier into standby mode
        ''' </summary>
        ''' <remarks></remarks>
        Public Sub EnterStandbyMode()
            If ReadyToSendMessage Then
                SendMessage("S")
            End If
        End Sub

        ''' <summary>
        ''' Put the amplifier into standby mode
        ''' </summary>
        ''' <remarks></remarks>
        Public Sub GetCurrentFrequencySegmentInfo()
            If ReadyToSendMessage Then
                SendMessage("W7")
            End If
        End Sub

        ''' <summary>
        ''' Put the amplifier into operate mode
        ''' </summary>
        ''' <remarks></remarks>
        Public Sub EnterOperateMode()
            If ReadyToSendMessage Then
                SendMessage("O")
            End If
        End Sub

        ''' <summary>
        ''' Selects the specified antenna
        ''' </summary>
        ''' <param name="AntennaNumber">The antenna to select</param>
        ''' <remarks></remarks>
        Public Sub SelectAntenna(ByVal AntennaNumber As Integer)
            If AntennaNumber < 0 Or AntennaNumber > 9 Then
                Throw New ArgumentException("AntennaNumber must be between 0 and 9")
            End If
            If ReadyToSendMessage Then
                SendMessage("W3" & AntennaNumber.ToString())
            End If
        End Sub


        Public Sub SetFrequencyBand(ByVal FrequencyHertz As Integer)
            Dim FrequencyKhz As Integer = FrequencyHertz \ 1000
            Dim SelectedBandSegment As BandSegment = BandSegment.GetSegmentFromFrequency(FrequencyKhz)

            If SelectedBandSegment IsNot Nothing Then
                SendMessage("W2" & EncodeACOMFormatNumber(SelectedBandSegment.SegmentID))
            End If
        End Sub

        ''' <summary>
        ''' Tells the ACOM2000A to return it's amplifier information 'R'
        ''' </summary>
        ''' <remarks></remarks>
        Public Sub GetAmplifierInformation()
            If ReadyToSendMessage Then
                SendMessage("R")
            End If
        End Sub

        ''' <summary>
        ''' 
        ''' </summary>
        ''' <param name="Number"></param>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Private Function EncodeACOMFormatNumber(ByVal Number As Integer) As String

            Dim LowByte As Integer = Number And &HF0
            Dim HighByte As Integer = Number And &HF

            Return Chr((LowByte \ 16) + 48) & Chr(HighByte + 48)

        End Function

#End Region

#Region " Public Methods "

        ''' <summary>
        ''' Sends a message to the ACOM2000A network
        ''' </summary>
        ''' <param name="Message"></param>
        ''' <remarks></remarks>
        Public Sub SendMessage(ByVal Message As String)
            SendMessage(GenerateMessageFrame(Message))
        End Sub

#End Region

#Region " Private Methods "

        ''' <summary>
        ''' Gets the measurement character code for a given measurement metric
        ''' </summary>
        ''' <param name="Metric"></param>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Private Shared Function GetMeasurmentMetricCharacter(ByVal Metric As MeasurementMetricType) As String
            Select Case Metric
                Case MeasurementMetricType.Bias
                    Return "b"
                Case MeasurementMetricType.DCInput
                    Return "e"
                Case MeasurementMetricType.Drive
                    Return "f"
                Case MeasurementMetricType.Frequency
                    Return "h"
                Case MeasurementMetricType.ForwardPower
                    Return "i"
                Case MeasurementMetricType.FilamentVoltage
                    Return "j"
                Case MeasurementMetricType.PowerGain
                    Return "k"
                Case MeasurementMetricType.HV
                    Return "l"
                Case MeasurementMetricType.IFFrontTube
                    Return "m"
                Case MeasurementMetricType.IFRearTube
                    Return "n"
                Case MeasurementMetricType.GridCurrent
                    Return "o"
                Case MeasurementMetricType.PlateCurrent
                    Return "p"
                Case MeasurementMetricType.ScreenCurrent
                    Return "q"
                Case MeasurementMetricType.MainsVoltage
                    Return "r"
                Case MeasurementMetricType.PlateRFVoltage
                    Return "s"
                Case MeasurementMetricType.ReflectedPower
                    Return "t"
                Case MeasurementMetricType.ScreenVoltage
                    Return "w"
                Case MeasurementMetricType.FrontTubeTemp
                    Return "x"
                Case MeasurementMetricType.RearTubeTemp
                    Return "y"
                Case MeasurementMetricType.VSWR
                    Return "z"
            End Select

            Return ""
        End Function

        ''' <summary>
        ''' Sends a message to the ACOM2000A network
        ''' </summary>
        ''' <param name="Message"></param>
        ''' <remarks></remarks>
        Private Sub SendMessage(ByVal Message As Byte())
            If ReadyToSendMessage Then
                m_RS232.SendData(Message)
            End If
        End Sub

        ''' <summary>
        ''' Generates a message frame with the appropriate Destination, Source and Terminator bytes
        ''' </summary>
        ''' <param name="Command"></param>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Private Function GenerateMessageFrame(ByVal Command As String) As Byte()

            Dim Frame As New List(Of Byte)

            Frame.Add(CByte(m_ACOMNetworkACOM2000AAddress)) 'Destination Address
            Frame.Add(CByte(m_ACOMNetworkConnectionAddress)) 'Source Address
            For Each c As Char In Command.ToCharArray
                Frame.Add(CByte(Asc(c)))
            Next
            Frame.Add(0) 'Message Terminator
            Return Frame.ToArray

        End Function

        ''' <summary>
        ''' Generates a message frame with the appropriate Broadcast, Source and Terminator bytes
        ''' </summary>
        ''' <param name="Command"></param>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Private Function GenerateBroadcastMessageFrame(ByVal Command As String) As Byte()

            Dim Frame As New List(Of Byte)
            Frame.Add(Constants.ACOMNETWORK_BROADCAST_ADDRESS) 'Destination Address
            Frame.Add(CByte(m_ACOMNetworkConnectionAddress)) 'Source Address
            For Each c As Char In Command.ToCharArray
                Frame.Add(CByte(Asc(c)))
            Next
            Frame.Add(0) 'Message Terminator
            Return Frame.ToArray

        End Function

#End Region

#Region " IDisposable Support "
        Private disposedValue As Boolean ' To detect redundant calls

        ' IDisposable
        Protected Overridable Sub Dispose(ByVal disposing As Boolean)
            If Not Me.disposedValue Then
                If disposing Then
                    If IsConnected Then
                        Disconnect()
                    End If
                    If m_RS232 IsNot Nothing Then
                        m_RS232.Disconnect()
                        m_RS232.Dispose()
                        m_RS232 = Nothing
                    End If

                    If m_RemotePowerOnRS232Connection IsNot Nothing Then
                        m_RemotePowerOnRS232Connection.Disconnect()
                        m_RemotePowerOnRS232Connection.Dispose()
                        m_RemotePowerOnRS232Connection = Nothing
                    End If
                End If
            End If
            Me.disposedValue = True
        End Sub

        ' This code added by Visual Basic to correctly implement the disposable pattern.
        Public Sub Dispose() Implements IDisposable.Dispose
            ' Do not change this code.  Put cleanup code in Dispose(ByVal disposing As Boolean) above.
            Dispose(True)
            GC.SuppressFinalize(Me)
        End Sub
#End Region

#Region " Shared Methods "

        Public Shared Function GetMeasurementTitle(ByVal Metric As MeasurementMetricType) As String

            Select Case Metric
                Case MeasurementMetricType.Bias
                    Return "BIAS    "
                Case MeasurementMetricType.DCInput
                    Return "DC-INPUT"
                Case MeasurementMetricType.Drive
                    Return "DRIVE   "
                Case MeasurementMetricType.Frequency
                    Return "FREQ.   "
                Case MeasurementMetricType.ForwardPower
                    Return "FWD-P   "
                Case MeasurementMetricType.FilamentVoltage
                    Return "FIL-V   "
                Case MeasurementMetricType.PowerGain
                    Return "GAIN    "
                Case MeasurementMetricType.HV
                    Return "HV      "
                Case MeasurementMetricType.IFFrontTube
                    Return "IF-FRONT"
                Case MeasurementMetricType.IFRearTube
                    Return "IF-REAR "
                Case MeasurementMetricType.GridCurrent
                    Return "I-GRID  "
                Case MeasurementMetricType.PlateCurrent
                    Return "I-PLATE "
                Case MeasurementMetricType.ScreenCurrent
                    Return "I-SCREEN"
                Case MeasurementMetricType.MainsVoltage
                    Return "MAINS   "
                Case MeasurementMetricType.PlateRFVoltage
                    Return "PLATE-RF"
                Case MeasurementMetricType.ReflectedPower
                    Return "RFL-P   "
                Case MeasurementMetricType.ScreenVoltage
                    Return "SCREEN-V"
                Case MeasurementMetricType.FrontTubeTemp
                    Return "TEMP-F  "
                Case MeasurementMetricType.RearTubeTemp
                    Return "TEMP-R  "
                Case MeasurementMetricType.VSWR
                    Return "VSWR    "
            End Select

            Return "UNKNOWN"
        End Function

#End Region

#Region " Event Handlers "

        Private Sub m_TimeoutTimer_Elapsed(ByVal sender As Object, ByVal e As System.Timers.ElapsedEventArgs) Handles m_TimeoutTimer.Elapsed
            m_TimeoutTimer.Stop()

            If m_DisconnectOnTimeout Then
                Disconnect()
            End If

            RaiseEvent ConnectionTimeout(Me, New EventArgs)
        End Sub

        Private Sub m_PowerOnTimer_Elapsed(ByVal sender As Object, ByVal e As System.Timers.ElapsedEventArgs) Handles m_PowerOnTimer.Elapsed
            m_PowerOnTimer.Stop()

            m_RemotePowerOnRS232Connection.RtsEnable = False
            m_RemotePowerOnRS232Connection.DtrEnable = False
            m_RemotePowerOnRS232Connection.Disconnect()
            m_RemotePowerOnRS232Connection.Dispose()
            m_RemotePowerOnRS232Connection = Nothing

            If m_WasConnectedBeforePowerON Then
                Dim RS232Parameters As New Framework.RS232.RS232PortParameters(1200, m_COMPort, False, False, IO.Ports.StopBits.One, 8, IO.Ports.Handshake.None, IO.Ports.Parity.None)
                m_RS232.Connect(RS232Parameters)
            End If
        End Sub

#End Region

    End Class

End Namespace